#include <stdlib.h>

#include "board.h"
#include "pin_mux.h"
#include "fsl_clock_config.h"
#include "fsl_dmamux.h"
#include "fsl_debug_console.h"

#include "fsl_wm8960.h"
#include "audio.h"
#include "mytask.h"

/* SAI instance and clock */
#define DEMO_CODEC_WM8960	(1U)
#define DEMO_SAI_CHANNEL	(0)
#define DEMO_SAI_BITWIDTH 	(kSAI_WordWidth16bits)
#define DEMO_SAI_IRQ		SAI1_IRQn
#define SAI_TxIRQHandler	SAI1_IRQHandler

/* IRQ */
#define DEMO_SAI_TX_IRQ		SAI1_IRQn
#define DEMO_SAI_RX_IRQ		SAI1_IRQn

/* DMA */
#define EXAMPLE_DMA		DMA0
#define EXAMPLE_DMAMUX		DMAMUX
#define EXAMPLE_TX_CHANNEL	(0U)
#define EXAMPLE_RX_CHANNEL	(1U)
#define EXAMPLE_SAI_TX_SOURCE	kDmaRequestMuxSai1Tx
#define EXAMPLE_SAI_RX_SOURCE	kDmaRequestMuxSai1Rx

/* 选择Audio PLL的时钟源 */
#define DEMO_SAI1_CLOCK_SOURCE_SELECT		(2U)
/* 预分频系数 */
#define DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER	(0U)
/* 后分频系数 */
#define DEMO_SAI1_CLOCK_SOURCE_DIVIDER		(63U)
/* 获取SAI的clock */
#define DEMO_SAI_CLK_FREQ                                                        \
	(CLOCK_GetFreq(kCLOCK_AudioPllClk) / (DEMO_SAI1_CLOCK_SOURCE_DIVIDER + 1U) / \
	(DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER + 1U))

/* 采样和buffer相关设置 */
#define OVER_SAMPLE_RATE	(384U)

/* 缓存buffer定义，定义4个缓存buffer */
// AT_NONCACHEABLE_SECTION_ALIGN(uint8_t Buffer[BUFFER_NUMBER * BUFFER_SIZE_BYTES], 4);
AT_NONCACHEABLE_SECTION_INIT(sai_edma_handle_t txHandle);
AT_NONCACHEABLE_SECTION_INIT(sai_edma_handle_t rxHandle);

edma_handle_t dmaTxHandle = {0}, dmaRxHandle= {0};
codec_handle_t codecHandle = {0};

/* 测试用变量 */
volatile uint8_t tx_over_flag = 0;
volatile uint8_t tx_buf_flag = 0;
volatile uint8_t start_point_flag = 0;	//用以判断是否检测到起始点，0为未检测到起始点，1为检测到起始点
// int16_t * tx_test_buf;

/* 多个缓存变量声明 */
uint8_t *rx_buf;
int16_t *audio_buf;
int16_t *pre_deal_buf;
sai_transfer_t xfer;
/* audio_buf标志量  当前缓存满的buffer值，0或1*/
volatile uint8_t flag_audio_buf = 0;

/*
 * AUDIO PLL setting: Frequency = Fref * (DIV_SELECT + NUM / DENOM)
 *                              = 24 * (32 + 77/100)
 *                              = 786.48 MHz
 */
const clock_audio_pll_config_t audioPllConfig = {
    .loopDivider = 32,		/* PLL loop divider. Valid range for DIV_SELECT divider value: 27~54. */
    .postDivider = 1,		/* Divider after the PLL, should only be 1, 2, 4, 8, 16. */
    .numerator = 77,		/* 30 bit numerator of fractional loop divider. */
    .denominator = 100,		/* 30 bit denominator of fractional loop divider */
};

/** 
 *@brief 使能mclk的引脚未输出设置 
 *@para  enable.1,使用输出,0关闭输出
 */
void BOARD_EnableSaiMclkOutput(bool enable)
{
	if (enable)
	{
		IOMUXC_GPR->GPR1 |= IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK;
	} else {
		IOMUXC_GPR->GPR1 &= (~IOMUXC_GPR_GPR1_SAI1_MCLK_DIR_MASK);
	}
}

/*
 *@brief rx的回调函数，只做emptyBlock的减
*/
static void rx_callback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData)
{
	if(kStatus_SAI_RxError == status)
	{
		/* 出错处理 */
		PRINTF("kStatus_SAI_RxError\r\n");
	} else {
		SAI_TransferReceiveEDMA(DEMO_SAI, &rxHandle, &xfer);
		xfer.data = rx_buf + flag_audio_buf * BUFFER_SIZE_BYTES;
		// if (flag_audio_buf)
		// {
		flag_audio_buf = flag_audio_buf ^ 1;
		// }
		if(start_point_flag)
		{
			xSemaphore_save.release();

		} else {
			xSemaphore_vad.release();
		}
	}
}

/*
 *@brief tx的回调函数，只做emptyBlock的加
*/
static void tx_callback(I2S_Type *base, sai_edma_handle_t *handle, status_t status, void *userData)
{
	if(kStatus_SAI_TxError == status)
	{
		/* 出错处理 */
	}
	else
	{
		// PRINTF("Enter TX CALL back\r\n");
		tx_over_flag = 0;
	}
}

/*
 *@brief 音频数据预处理，取单声道数据，并存储在pre_deal_buf中
*/
void audio_data_pre_deal(int16_t *data_buf)
{
	volatile uint32_t i = 0;
	for(i =0; i < NUM_FRAM_SAMPLE; i ++)
	{
		pre_deal_buf[i] = data_buf[2 * i];
	}
}

void sai_edma_set(void)
{
	uint32_t mclkSourceClockHz = 0U;
	
	sai_config_t config;
	sai_transfer_format_t format;
	edma_config_t dmaConfig = {0};

	/* audio_buf内存分配，用来存储有效音频数据段，最长时长为 AUDIO_BUFFER_LENGTH_MS ms */
	audio_buf = (int16_t *)malloc(sizeof(int16_t) * AUDIO_BUFFER_LENGTH_SAMPLE);  // 存储2s音频数据需要64kByte的空间
	if (audio_buf == NULL)
	{
		PRINTF("The audio_buf malloc failed\r\n");
	} else {
		memset(audio_buf, 0, sizeof(int16_t) * AUDIO_BUFFER_LENGTH_SAMPLE);
		PRINTF("The audio_buf malloc success\r\n");
	}
	/* rx_buf内存分配，存储DMA从i2s处获取的音频数据，长度为一帧数据点数 * 2，双缓存模式 */
	rx_buf = (uint8_t *)malloc(sizeof(uint8_t) * BUFFER_NUMBER * BUFFER_SIZE_BYTES); // 双缓冲，每个Buf缓冲一帧，640个采样点。5kBytes的空间
	if (rx_buf == NULL)
	{
		PRINTF("The rx_buf malloc failed\r\n");
	} else {
		memset(rx_buf, 0, sizeof(uint8_t) * BUFFER_NUMBER * BUFFER_SIZE_BYTES);
		PRINTF("The rx_buf malloc success\r\n");	
	}
	/* pre_deal_buf，音频数据预处理缓存，取单声道数据 */
	pre_deal_buf = (int16_t *)malloc(sizeof(int16_t) * NUM_FRAM_SAMPLE); // 预处理缓存，大小约为1kBytes
	if (rx_buf == NULL)
	{
		PRINTF("The pre_deal_buf malloc failed\r\n");
	} else {
		memset(pre_deal_buf, 0, sizeof(int16_t) * NUM_FRAM_SAMPLE);
		PRINTF("The pre_deal_buf malloc success\r\n");	
	}

	CLOCK_InitAudioPll(&audioPllConfig);

	/* SAI1的时钟设置 */
	CLOCK_SetMux(kCLOCK_Sai1Mux, DEMO_SAI1_CLOCK_SOURCE_SELECT);
	CLOCK_SetDiv(kCLOCK_Sai1PreDiv, DEMO_SAI1_CLOCK_SOURCE_PRE_DIVIDER);
	CLOCK_SetDiv(kCLOCK_Sai1Div, DEMO_SAI1_CLOCK_SOURCE_DIVIDER);

	/* 使能MCLK并初始化LPI2C */
	BOARD_EnableSaiMclkOutput(true);

	/* 初始化DMA */
	EDMA_GetDefaultConfig(&dmaConfig);
	EDMA_Init(EXAMPLE_DMA, &dmaConfig);
	EDMA_CreateHandle(&dmaTxHandle, EXAMPLE_DMA, EXAMPLE_TX_CHANNEL);
	EDMA_CreateHandle(&dmaRxHandle, EXAMPLE_DMA, EXAMPLE_RX_CHANNEL);

	/* 初始化DMA MUX */
	DMAMUX_Init(EXAMPLE_DMAMUX);
	DMAMUX_SetSource(EXAMPLE_DMAMUX, EXAMPLE_TX_CHANNEL, (uint8_t)EXAMPLE_SAI_TX_SOURCE);
	DMAMUX_EnableChannel(EXAMPLE_DMAMUX, EXAMPLE_TX_CHANNEL);
	DMAMUX_SetSource(EXAMPLE_DMAMUX, EXAMPLE_RX_CHANNEL, (uint8_t)EXAMPLE_SAI_RX_SOURCE);
	DMAMUX_EnableChannel(EXAMPLE_DMAMUX, EXAMPLE_RX_CHANNEL);

	/* SAI Tx模块初始化，使用默认值来配置 */
	/*
	 * config.masterSlave = kSAI_Master;
	 * config.mclkSource = kSAI_MclkSourceSysclk;
	 * config.protocol = kSAI_BusLeftJustified;
	 * config.syncMode = kSAI_ModeAsync;
	 * config.mclkOutputEnable = true;
	 */
	SAI_TxGetDefaultConfig(&config);
	config.protocol = kSAI_BusI2S;
	SAI_TxInit(DEMO_SAI, &config);

	/* SAI Rx模块初始化，使用默认值来配置 */
	SAI_RxGetDefaultConfig(&config);
	config.protocol = kSAI_BusI2S;
	SAI_RxInit(DEMO_SAI, &config);

	/* 音频格式设置16k采样，16bit位宽 */
	format.bitWidth = kSAI_WordWidth16bits;
	format.channel = 0U;
	format.sampleRate_Hz = kSAI_SampleRate16KHz;
	format.masterClockHz = DEMO_SAI_CLK_FREQ;
	format.protocol = config.protocol;
	format.stereo = kSAI_Stereo;
	format.isFrameSyncCompact = false;
	format.watermark = FSL_FEATURE_SAI_FIFO_COUNT / 2U;
	
	/* 使用默认配置初始化WM8960 */
	WM8960_Init(NULL);
	WM8960_ConfigDataFormat(format.masterClockHz, format.sampleRate_Hz, format.bitWidth);

	SAI_TransferTxCreateHandleEDMA(DEMO_SAI, &txHandle, tx_callback, NULL, &dmaTxHandle);
	SAI_TransferRxCreateHandleEDMA(DEMO_SAI, &rxHandle, rx_callback, NULL, &dmaRxHandle);
	mclkSourceClockHz = DEMO_SAI_CLK_FREQ;
	SAI_TransferTxSetFormatEDMA(DEMO_SAI, &txHandle, &format, mclkSourceClockHz, format.masterClockHz);
	SAI_TransferRxSetFormatEDMA(DEMO_SAI, &rxHandle, &format, mclkSourceClockHz, format.masterClockHz);

	xfer.data = rx_buf + flag_audio_buf * BUFFER_SIZE_BYTES;
	xfer.dataSize = BUFFER_SIZE_BYTES;
	flag_audio_buf = 1;
	SAI_TransferReceiveEDMA(DEMO_SAI, &rxHandle, &xfer);
	
	while(1)
	{

	}
}
